
export class UIUtils {
    /**
     * 
     * @param path 
     * @param parent 
     * @param action forced: 同名动画强制重新开始
     */
    public static playSkeleton(path: string, parent: cc.Node, action: { ani: string, loop: boolean, endHide?: boolean, callback?: Function; caller?: any; forced?: boolean; }) {
        let actionNode = this.getChildByPath(path, parent);
        let spine: sp.Skeleton = actionNode.getComponent(sp.Skeleton);
        spine.node.active = true;

        if (action.ani == spine.animation && !action.forced) return;// 同名动画在不强制刷新的情况下不重新播放动画

        spine.setAnimation(0, action["ani"], action["loop"]);
        spine.setCompleteListener(() => {
            spine.setCompleteListener(null);

            if (action.callback) {
                if (action.caller) {
                    action.callback.call(action.caller);
                }
                else {
                    action.callback();
                }
            }

            if (action['endHide'] == true)
                spine.node.active = false;
        });
    }
    /**
    * 设置指定节点 Label 组件的字符
    * @param path 节点名路径，多层级用 "." 字符分隔
    * @param string 需要设置的字符串
    */
    public static setString(path: string, parent: cc.Node, string: string | number): boolean {
        let node = this.getChildByPath(path, parent);
        let label = node && node.getComponent(cc.Label);

        string = String(string);

        if (label instanceof cc.Label) {
            label.string = string;
            return true;
        }
        console.warn(`${path} setString error...`);
        return false;
    }

    /**
       * 为节点设置图片
       * @param path 节点名路径，多层级用 "." 字符分隔
       * @param sf 图片
       */
    public static setSpriteFrame(path: string, parent: cc.Node, sf: cc.SpriteFrame): boolean {
        let node = this.getChildByPath(path, parent);
        let sprite = node && node.getComponent(cc.Sprite);

        if (sprite instanceof cc.Sprite && (sf instanceof cc.SpriteFrame || sf === null)) {
            sprite.spriteFrame = sf;
            return true;
        }
        console.warn(`${path} setSpriteFrame error...`);
        return false;
    }

    /**
       * 切换显示指定节点
       * @param path 节点名路径，多层级用 "." 字符分隔
       */
    public static setVisable(path: string, parent: cc.Node, bool?: boolean): void {
        let node = this.getChildByPath(path, parent);
        if (node) {
            if (typeof bool === 'boolean') {
                node.active = bool;
            }
            else {
                node.active = !node.active;
            }
        }
    }
    /**
    * 给节点添加点击事件
    * @param path 节点名路径，多层级用 "." 字符分隔
    * @param callback 回调函数
    * @param isScale 点击是否有缩放效果
    * @param parent 查找节点指定父节点
    * @returns 
    */
    public static addClick(path: string, parent: cc.Node, caller: any, callback: Function, isScale = true) {
        let node = this.getChildByPath(path, parent);

        if (!node) return;

        let btn = node.getComponent(cc.Button);
        if (!btn) {
            btn = node.addComponent(cc.Button);
        }
        if (isScale) {
            btn.target = node;
            btn.transition = cc.Button.Transition.SCALE;
            btn.duration = 0.1;
            btn.zoomScale = 0.85;
        }

        node.targetOff(caller);
        node.on('click', (event, t) => {
            this._noFastClick(event, caller, callback, 500);
        }, this);
        return node;
    }

    /**
     * 防止快速点击的方法
     * @param event 任意对象
     * @param func 回调方法
     * @param time 冷却时间,单位：毫秒
     */
    public static _noFastClick(event, caller: any, func, time?: number) {
        if (event && event.target) {
            if (event.target._clickTime && new Date().getTime() - event.target._clickTime < (time ? time : 500)) {
                return;
            }
            event.target._clickTime = new Date().getTime();
        }
        func.call(caller, event);
    }

    /**
    * 通过子节点路径查找节点
    * @param path 子节点路径，多层级用 "." 字符分隔
    * @param parent 
    * @returns 
    */
    public static getChildByPath<T extends cc.Node>(path: string, parent: cc.Node): T {
        if (path == null) return parent as T;
        let paths: string[] = path.split('.');
        let target = parent;
        for (let index = 0; index < paths.length; index++) {
            let childName = paths[index];
            if (target == null) {
                let parentpath = this._getParentPath(parent);
                console.warn(parentpath + "." + path + " is not find");
                break;
            }
            target = target.getChildByName(childName);
        }

        if (target)
            return target as T;

        let parentpath = this._getParentPath(parent);
        console.warn(parentpath + "." + name + " is not find");
        return null;
    }

    protected static _getParentPath(node) {
        if (node == null)
            return null;
        let parentname = this._getParentPath(node.parent);
        if (parentname != null)
            parentname = parentname + "." + node.name;
        else
            parentname = node.name;
        return parentname;
    }

    /**
    * 将 cc.tween 动画执行风格转为 promise
    * @param target 
    * @param tween 
    * @returns 
    */
    public static runTween(target, tween: cc.Tween): Promise<boolean> {
        return new Promise<boolean>(succ => {
            cc.tween(target).then(tween).call(succ).start();
        });
    }
}